//
//  Params.cpp
//  RayTracer
//
//  Created by 俞云康 on 3/16/16.
//  Copyright © 2016 yushroom. All rights reserved.
//

#include "Params.hpp"


int Params::getIntAttribute(const string& name) const {
    auto attr = _node.attribute(name.c_str());
    if (attr.empty()) {
        error("empty attribute %s from node: %s\n", name.c_str(), _node.name());
        abort();
    }
    return attr.as_int();
}

int Params::getIntAttribute(const string& name, const int default_value, bool ignore_warning) const {
    auto attr = _node.attribute(name.c_str());
    if (attr.empty()) {
        if (!ignore_warning)
            warning("empty attribute %s from node: %s, use default value: %d\n", name.c_str(), _node.name(), default_value);
        return default_value;
    }
    return attr.as_int();
}

float Params::getFloatAttribute(const string& name) const {
    auto attr = _node.attribute(name.c_str());
    if (attr.empty()) {
        error("empty attribute %s from node: %s\n", name.c_str(), _node.name());
        abort();
    }
    return attr.as_float();
}

float Params::getFloatAttribute(const string& name, const float default_value, bool ignore_warning) const {
    auto attr = _node.attribute(name.c_str());
    if (attr.empty()) {
        if (!ignore_warning)
            warning("empty attribute %s from node: %s, use default value: %f\n", name.c_str(), _node.name(), default_value);
        return default_value;
    }
    return attr.as_float();
}

string Params::getStringAttribute(const string& name) const {
    auto attr = _node.attribute(name.c_str());
    if (attr.empty()) {
        error("empty attribute %s from node: %s\n", name.c_str(), _node.name());
        abort();
    }
    return attr.as_string();
}

string Params::getStringAttribute(const string& name, const string& default_value, bool ignore_warning) const {
    auto attr = _node.attribute(name.c_str());
    if (attr.empty()) {
        if (!ignore_warning)
            warning("empty attribute %s from node: %s, use default value: %s\n", name.c_str(), _node.name(), default_value.c_str());
        return default_value;
    }
    return attr.as_string();
}

int Params::getInt() const {
    return child("int").getIntAttribute("value");
}

int Params::getInt(const string& name) const {
    return namedChild(name).getIntAttribute("value");
}

float Params::getFloat() const {
    return child("float").getFloatAttribute("value");
}

float Params::getFloat(const string& name) const {
    return namedChild(name).getFloatAttribute("value");
}

string Params::getString() const {
    return child("string").getStringAttribute("value");
}

string Params::getString(const string& name) const {
    return namedChild(name).getStringAttribute("value");
}

float3 Params::getFloat3() const {
    float3 c;
    Params cp = child("float3");
    c.x = cp.getFloatAttribute("x");
    c.y = cp.getFloatAttribute("y");
    c.z = cp.getFloatAttribute("z");
    return c;
}

float3 Params::getFloat3(const string& name) const {
    float3 c;
    Params cp = namedChild(name);
    c.x = cp.getFloatAttribute("x");
    c.y = cp.getFloatAttribute("y");
    c.z = cp.getFloatAttribute("z");
    return c;
}

Color Params::getColor() const {
    Color c;
    Params cp = child("color");
    c.r = cp.getFloatAttribute("r");
    c.g = cp.getFloatAttribute("g");
    c.b = cp.getFloatAttribute("b");
    return c;
}

Color Params::getColor(const string& name) const {
    Color c;
    Params cp = namedChild(name);
    c.r = cp.getFloatAttribute("r");
    c.g = cp.getFloatAttribute("g");
    c.b = cp.getFloatAttribute("b");
    return c;
}


string Params::getType() const {
    return getStringAttribute("type", "", true);
}

string Params::getName() const {
    return getStringAttribute("name", "", true);;
}

string Params::getID() const {
    return getStringAttribute("id", "", true);
}

string Params::getRef() const {
    return getStringAttribute("ref", "", true);
}


// get child node by type
Params Params::child(const string& type_name) const {
    return Params(_node.child(type_name.c_str()));
}

void Params::children(vector<string>& names, vector<Params>& ps) const {
    for (pugi::xml_node node : _node.children()) {
        names.push_back(node.name());
        ps.push_back(Params(node));
    }
}

// get child node by name
Params Params::namedChild(const string& name) const {
    for (pugi::xml_node node : _node.children()) {
        if (string(node.attribute("name").as_string()) == name) {
            return Params(node);
        }
    }
    error("namedChild %s not found", name.c_str());
    abort();
}

bool Params::hasNamedChild(const string& name) const {
	bool found = false;
	for (pugi::xml_node node : _node.children()) {
		if (string(node.attribute("name").as_string()) == name) {
			found = true;
			break;
		}
	}
	return found;
}

bool Params::hasTypedChild(const string& type) const {
	bool found = false;
	for (pugi::xml_node node : _node.children()) {
		if (node.name() == type) {
			found = true;
			break;
		}
	}
	return found;
}